#include "wm_spi.h"


static void SPI_DMATransmitCplt(DMA_HandleTypeDef *hdma);
static void SPI_DMAHalfTransmitCplt(DMA_HandleTypeDef *hdma);
static void SPI_DMAReceiveCplt(DMA_HandleTypeDef *hdma);
static void SPI_DMAHalfReceiveCplt(DMA_HandleTypeDef *hdma);
static void SPI_DMATransmitReceiveCplt(DMA_HandleTypeDef *hdma);
static void SPI_DMAHalfTransmitReceiveCplt(DMA_HandleTypeDef *hdma);
static void SPI_Transmit_IT(SPI_HandleTypeDef *hspi);
static void SPI_EndTransmit_IT(SPI_HandleTypeDef *hspi);
static void SPI_Receive_IT(SPI_HandleTypeDef *hspi);
static void SPI_EndReceive_IT(SPI_HandleTypeDef *hspi);

/**
  * @brief  Initialize the SPI according to the specified parameters
  *         in the SPI_InitTypeDef and initialize the associated handle.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)
{
	if (hspi == NULL)
	{
		return HAL_ERROR;
	}
	
	assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));
	assert_param(IS_SPI_MODE(hspi->Init.Mode));
	assert_param(IS_SPI_DIRECTION(hspi->Init.Direction));
	assert_param(IS_SPI_DATASIZE(hspi->Init.DataSize));
	assert_param(IS_SPI_NSS(hspi->Init.NSS));
	assert_param(IS_SPI_BAUDRATE_PRESCALER(hspi->Init.BaudRatePrescaler));
	assert_param(IS_SPI_CPOL(hspi->Init.CLKPolarity));
    assert_param(IS_SPI_CPHA(hspi->Init.CLKPhase));
	assert_param(IS_SPI_BIG_OR_LITTLE(hspi->Init.FirstByte));
	
	if (hspi->State == HAL_SPI_STATE_RESET)
	{
		hspi->Lock = HAL_UNLOCKED;
		HAL_SPI_MspInit(hspi);
	}
	hspi->State = HAL_SPI_STATE_BUSY;
	
	__HAL_SPI_DISABLE_TXRX(hspi);
	
	WRITE_REG(hspi->Instance->CH_CFG, (hspi->Init.NSS | SPI_CH_CFG_CLEARFIFOS));
	WRITE_REG(hspi->Instance->SPI_CFG, (hspi->Init.Mode | hspi->Init.CLKPolarity | hspi->Init.CLKPhase | hspi->Init.FirstByte));
	WRITE_REG(hspi->Instance->CLK_CFG, hspi->Init.BaudRatePrescaler);
	
	__HAL_SPI_SET_CS_HIGH(hspi);
	
	hspi->ErrorCode = HAL_SPI_ERROR_NONE;
	hspi->State     = HAL_SPI_STATE_READY;
	
	return HAL_OK;
}

/**
  * @brief  De-Initialize the SPI peripheral.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)
{
	if (hspi == NULL)
	{
		return HAL_ERROR;
	}
	
	assert_param(IS_SPI_ALL_INSTANCE(hspi->Instance));
	
	hspi->State = HAL_SPI_STATE_BUSY;
	__HAL_SPI_DISABLE_TXRX(hspi);
	HAL_SPI_MspDeInit(hspi);
	
	hspi->ErrorCode = HAL_SPI_ERROR_NONE;
	hspi->State = HAL_SPI_STATE_RESET;
	__HAL_UNLOCK(hspi);
	
	return HAL_OK;
}

/**
  * @brief  Initialize the SPI MSP.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval None
  */
__attribute__((weak)) void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
	UNUSED(hspi);
}

/**
  * @brief  De-Initialize the SPI MSP.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval None
  */
__attribute__((weak)) void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi)
{
	UNUSED(hspi);
}

/**
  * @brief  Transmit an amount of data in blocking mode.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pData pointer to data buffer
  * @param  Size amount of data to be sent
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size, uint32_t Timeout)
{
	uint32_t tickstart, data = 0, i = 0;
	HAL_StatusTypeDef errorcode = HAL_OK;
	uint32_t fifo_count = 0, block_cnt = 0, tx_block_cnt = 0, tx_size = 0;
	
	__HAL_LOCK(hspi);
	
	tickstart = HAL_GetTick();
	
	if (hspi->State != HAL_SPI_STATE_READY)
	{
		errorcode = HAL_BUSY;
		goto error;
	}

	if ((pData == NULL) || (Size == 0U))
	{
		errorcode = HAL_ERROR;
		goto error;
	}
	
	__HAL_SPI_CLEAR_FIFO(hspi);
	__HAL_SPI_ENABLE_TX(hspi);
	hspi->State       = HAL_SPI_STATE_BUSY_TX;
	hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
	
	hspi->pRxBuffPtr  = (uint8_t *)NULL;
	hspi->RxXferSize  = 0U;
	hspi->RxXferCount = 0U;
	
	block_cnt = Size / BLOCK_SIZE;
	while (tx_block_cnt <= block_cnt)
	{
		if (tx_block_cnt < block_cnt)
		{
			tx_size = BLOCK_SIZE;
		}
		else
		{
			tx_size = Size % BLOCK_SIZE;
		}
		hspi->pTxBuffPtr  = (uint8_t *)(pData + (tx_block_cnt * BLOCK_SIZE));
		hspi->TxXferSize  = tx_size;
		hspi->TxXferCount = tx_size;
		
		__HAL_SPI_SET_CLK_NUM(hspi, tx_size * 8);
		__HAL_SPI_SET_START(hspi);
		
		while (hspi->TxXferCount > 0U)
		{
			fifo_count = (32 - __HAL_SPI_GET_TXFIFO(hspi)) / 4;
			while((fifo_count > 0) && (hspi->TxXferCount > 0))
			{
				data = 0;
				for (i = 0; i < hspi->TxXferCount; i++)
				{
					if (i == 4)
					{
						break;
					}
					data |= (hspi->pTxBuffPtr[i] << (i * 8));
				}
				hspi->pTxBuffPtr += sizeof(uint8_t) * i;
				hspi->TxXferCount -= i;
				WRITE_REG(hspi->Instance->TXDATA, data);
				if (fifo_count > 0)
				{
					fifo_count--;
				}
			}
			if ((((HAL_GetTick() - tickstart) >=  Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
			{
				errorcode = HAL_TIMEOUT;
				goto error;
			}
		}
		while (__HAL_SPI_GET_FLAG(hspi, SPI_INT_SRC_DONE) != SPI_INT_SRC_DONE)
		{
			if ((((HAL_GetTick() - tickstart) >=  Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
			{
				errorcode = HAL_TIMEOUT;
				goto error;
			}
		}
		__HAL_SPI_CLEAR_FLAG(hspi, SPI_INT_SRC_DONE);
		
		tx_block_cnt++;
	}
error:
	__HAL_SPI_DISABLE_TX(hspi);
	hspi->State = HAL_SPI_STATE_READY;
	
	__HAL_UNLOCK(hspi);
	return errorcode;
}

/**
  * @brief  Receive an amount of data in blocking mode.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pData pointer to data buffer
  * @param  Size amount of data to be received
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size, uint32_t Timeout)
{
	uint32_t tickstart, data = 0, i = 0;
	HAL_StatusTypeDef errorcode = HAL_OK;
	uint32_t fifo_count = 0, block_cnt = 0, rx_block_cnt = 0, rx_size = 0;
	
	__HAL_LOCK(hspi);
	
	tickstart = HAL_GetTick();
	if (hspi->State != HAL_SPI_STATE_READY)
	{
		errorcode = HAL_BUSY;
		goto error;
	}
	
	if ((pData == NULL) || (Size == 0U))
	{
		errorcode = HAL_ERROR;
		goto error;
	}
	__HAL_SPI_CLEAR_FIFO(hspi);
	__HAL_SPI_ENABLE_RX(hspi);
	
	hspi->State       = HAL_SPI_STATE_BUSY_RX;
	hspi->ErrorCode   = HAL_SPI_ERROR_NONE;

	hspi->pTxBuffPtr  = (uint8_t *)NULL;
	hspi->TxXferSize  = 0U;
	hspi->TxXferCount = 0U;

	block_cnt = Size / BLOCK_SIZE;
	while (rx_block_cnt <=  block_cnt)
	{
		if (rx_block_cnt < block_cnt)
		{
			rx_size = BLOCK_SIZE;
		}
		else
		{
			rx_size = Size % BLOCK_SIZE;
		}
		hspi->pRxBuffPtr  = (uint8_t *)(pData + rx_block_cnt * BLOCK_SIZE);
		hspi->RxXferSize  = rx_size;
		hspi->RxXferCount = rx_size;
		
		__HAL_SPI_SET_CLK_NUM(hspi, rx_size * 8);
		__HAL_SPI_SET_START(hspi);
		
		while (hspi->RxXferCount > 0U)
		{
			fifo_count = __HAL_SPI_GET_RXFIFO(hspi) / 4;
			while ((fifo_count > 0) || (__HAL_SPI_GET_FLAG(hspi, SPI_INT_SRC_DONE) == SPI_INT_SRC_DONE))
			{
				data = READ_REG(hspi->Instance->RXDATA);
				for (i = 0; i < 4; i++)
				{
					if (i == hspi->RxXferCount)
					{
						break;
					}
					hspi->pRxBuffPtr[i] = (data >> (i * 8)) & 0xFF;
				}
				hspi->pRxBuffPtr += sizeof(uint8_t) * i;
				hspi->RxXferCount -= i;
				if (fifo_count > 0)
				{
					fifo_count--;
				}
				if((hspi->RxXferCount == 0))
				{
					break;
				}
			}
			
			if ((((HAL_GetTick() - tickstart) >=  Timeout) && ((Timeout != HAL_MAX_DELAY))) || (Timeout == 0U))
			{
				errorcode = HAL_TIMEOUT;
				goto error;
			}
		}
		while (__HAL_SPI_GET_FLAG(hspi, SPI_INT_SRC_DONE) != SPI_INT_SRC_DONE)
		{
			if ((((HAL_GetTick() - tickstart) >=  Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
			{
				errorcode = HAL_TIMEOUT;
				goto error;
			}
		}
		__HAL_SPI_CLEAR_FLAG(hspi, SPI_INT_SRC_DONE);
		
		rx_block_cnt++;
	}
error :
	__HAL_SPI_DISABLE_RX(hspi);
	hspi->State = HAL_SPI_STATE_READY;
	__HAL_UNLOCK(hspi);
	return errorcode;
}

/**
  * @brief  Transmit and Receive an amount of data in blocking mode.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pTxData pointer to transmission data buffer
  * @param  pRxData pointer to reception data buffer
  * @param  Size amount of data to be sent and received
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint32_t Size,
                                          uint32_t Timeout)
{
	HAL_StatusTypeDef    errorcode = HAL_OK;
	uint32_t tickstart, data = 0, i = 0;
	uint32_t fifo_count = 0, block_cnt = 0, tx_block_cnt = 0, tx_size = 0;

	__HAL_LOCK(hspi);
	
	tickstart = HAL_GetTick();
	
	if (!((hspi->State == HAL_SPI_STATE_READY) || (hspi->State == HAL_SPI_STATE_BUSY_RX)))
	{
		errorcode = HAL_BUSY;
		goto error;
	}

	if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U))
	{
		errorcode = HAL_ERROR;
		goto error;
	}
	
	if (hspi->State != HAL_SPI_STATE_BUSY_RX)
	{
		hspi->State = HAL_SPI_STATE_BUSY_TX_RX;
	}
	hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
	__HAL_SPI_CLEAR_FIFO(hspi);
	__HAL_SPI_ENABLE_TXRX(hspi);
	
	block_cnt = Size / BLOCK_SIZE;
	while (tx_block_cnt <= block_cnt)
	{
		if (tx_block_cnt < block_cnt)
		{
			tx_size = BLOCK_SIZE;
		}
		else
		{
			tx_size = Size % BLOCK_SIZE;
		}
		
		hspi->pRxBuffPtr  = (uint8_t *)(pRxData + (tx_block_cnt * BLOCK_SIZE));
		hspi->RxXferCount = tx_size;
		hspi->RxXferSize  = tx_size;
		hspi->pTxBuffPtr  = (uint8_t *)(pTxData + (tx_block_cnt * BLOCK_SIZE));
		hspi->TxXferCount = tx_size;
		hspi->TxXferSize  = tx_size;
		
		__HAL_SPI_SET_CLK_NUM(hspi, tx_size * 8);
		__HAL_SPI_SET_START(hspi);
		
		while ((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U))
		{
			fifo_count = (32 - __HAL_SPI_GET_TXFIFO(hspi)) / 4;
			while ((fifo_count > 0) && (hspi->TxXferCount > 0U))
			{
				data = 0;
				for (i = 0; i < hspi->TxXferCount; i++)
				{
					if (i == 4)
					{
						break;
					}
					data |= (hspi->pTxBuffPtr[i] << (i * 8));
				}
				hspi->pTxBuffPtr += sizeof(uint8_t) * i;
				hspi->TxXferCount -= i;
				WRITE_REG(hspi->Instance->TXDATA, data);
				if (fifo_count > 0)
				{
					fifo_count--;
				}
			}
			
			fifo_count = __HAL_SPI_GET_RXFIFO(hspi) / 4 ;
			while ((fifo_count > 0) || (__HAL_SPI_GET_FLAG(hspi, SPI_INT_SRC_DONE) == SPI_INT_SRC_DONE))
			{
				data = READ_REG(hspi->Instance->RXDATA);
				for (i = 0; i < 4; i++)
				{
					if (i == hspi->RxXferCount)
					{
						break;
					}
					hspi->pRxBuffPtr[i] = (data >> (i * 8)) & 0xFF;
				}
				hspi->pRxBuffPtr += sizeof(uint8_t) * i;
				hspi->RxXferCount -= i;
				if (fifo_count > 0)
				{
					fifo_count--;
				}
				if (hspi->RxXferCount == 0)
				{
					break;
				}
			}
			
			if ((((HAL_GetTick() - tickstart) >=  Timeout) && ((Timeout != HAL_MAX_DELAY))) || (Timeout == 0U))
			{
				errorcode = HAL_TIMEOUT;
				goto error;
			}
		}
		while (__HAL_SPI_GET_FLAG(hspi, SPI_INT_SRC_DONE) != SPI_INT_SRC_DONE)
		{
			if ((((HAL_GetTick() - tickstart) >=  Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
			{
				errorcode = HAL_TIMEOUT;
				goto error;
			}
		}
		__HAL_SPI_CLEAR_FLAG(hspi, SPI_INT_SRC_DONE);
		
		tx_block_cnt++;
	
	}
error :
	__HAL_SPI_DISABLE_TXRX(hspi);
	hspi->State = HAL_SPI_STATE_READY;
	__HAL_UNLOCK(hspi);
	return errorcode;
}

/**
  * @brief  Transmit an amount of data in non-blocking mode with Interrupt.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pData pointer to data buffer
  * @param  Size amount of data to be sent
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size)
{
	HAL_StatusTypeDef errorcode = HAL_OK;
	uint32_t len = 0, data = 0, i = 0;
	
	__HAL_LOCK(hspi);
	
	if (hspi->State != HAL_SPI_STATE_READY)
	{
		errorcode = HAL_BUSY;
		goto error;
	}
	
	if ((pData == NULL) || (Size == 0U))
	{
		errorcode = HAL_ERROR;
		goto error;
	}
	__HAL_SPI_CLEAR_FIFO(hspi);
	hspi->State = HAL_SPI_STATE_BUSY_TX;
	hspi->ErrorCode = HAL_SPI_ERROR_NONE;
	hspi->pTxBuffPtr = (uint8_t *)pData;
	hspi->TxXferSize = Size;
	hspi->TxXferCount = Size;
	
	hspi->pRxBuffPtr = (uint8_t *)NULL;
	hspi->RxXferSize = 0U;
	hspi->RxXferCount = 0U;
	
	len = (hspi->TxXferCount > BLOCK_SIZE) ? BLOCK_SIZE : hspi->TxXferCount;
	__HAL_SPI_SET_CLK_NUM(hspi, (len * 8));
	
	for (i = 0; i < hspi->TxXferCount; i++)
	{
		if (i == 4)
		{
			break;
		}
		data |= ((hspi->pTxBuffPtr + hspi->TxXferSize - hspi->TxXferCount)[i] << (i * 8));
	}
	hspi->Instance->TXDATA = data;
	hspi->TxXferCount -= i;
	
	__HAL_SPI_ENABLE_TX(hspi);
	__HAL_SPI_CLEAR_FLAG(hspi, (SPI_INT_SRC_DONE | SPI_INT_SRC_TXOV | SPI_INT_SRC_TXUN | SPI_INT_SRC_TXRDY));
	__HAL_SPI_ENABLE_IT(hspi, (SPI_INT_MASK_DONE | SPI_INT_MASK_TXUN | SPI_INT_SRC_TXRDY));
	
	__HAL_SPI_SET_START(hspi);
error:
	__HAL_UNLOCK(hspi);
	return errorcode;
}

/**
  * @brief  Receive an amount of data in non-blocking mode with Interrupt.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pData pointer to data buffer
  * @param  Size amount of data to be sent
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size)
{
	HAL_StatusTypeDef errorcode = HAL_OK;
	uint32_t len = 0;
	
	__HAL_LOCK(hspi);
	
	if (hspi->State != HAL_SPI_STATE_READY)
	{
		errorcode = HAL_BUSY;
		goto error;
	}
	
	if ((pData == NULL) || (Size == 0U))
	{
		errorcode = HAL_ERROR;
		goto error;
	}
	__HAL_SPI_CLEAR_FIFO(hspi);
	hspi->State       = HAL_SPI_STATE_BUSY_RX;
	hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
	hspi->pTxBuffPtr  = (uint8_t *)NULL;
	hspi->TxXferSize  = 0U;
	hspi->TxXferCount = 0U;
	
	hspi->pRxBuffPtr = (uint8_t *)pData;
	hspi->RxXferSize = Size;
	hspi->RxXferCount = Size;
	
	len = (hspi->RxXferCount > BLOCK_SIZE) ? BLOCK_SIZE : hspi->RxXferCount;
	__HAL_SPI_SET_CLK_NUM(hspi, (len * 8));
	
	__HAL_SPI_ENABLE_RX(hspi);
	__HAL_SPI_CLEAR_FLAG(hspi, (SPI_INT_SRC_DONE | SPI_INT_SRC_RXOV | SPI_INT_SRC_RXUN | SPI_INT_SRC_RXRDY));
	__HAL_SPI_ENABLE_IT(hspi, (SPI_INT_MASK_DONE | SPI_INT_MASK_RXOV | SPI_INT_SRC_RXRDY));
	
	__HAL_SPI_SET_START(hspi);
error:
	__HAL_UNLOCK(hspi);
	return errorcode;
}

/**
  * @brief  Transmit and Receive an amount of data in non-blocking mode with Interrupt.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pTxData pointer to transmission data buffer
  * @param  pRxData pointer to reception data buffer
  * @param  Size amount of data to be sent and received
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint32_t Size)
{
	HAL_StatusTypeDef errorcode = HAL_OK;
	uint32_t len = 0, data = 0, i = 0;
	
	__HAL_LOCK(hspi);
	
	if (hspi->State != HAL_SPI_STATE_READY)
	{
		errorcode = HAL_BUSY;
		goto error;
	}
	
	if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U))
	{
		errorcode = HAL_ERROR;
		goto error;
	}
	__HAL_SPI_CLEAR_FIFO(hspi);
	hspi->State = HAL_SPI_STATE_BUSY_TX_RX;
	hspi->ErrorCode = HAL_SPI_ERROR_NONE;
	hspi->pTxBuffPtr = (uint8_t *)pTxData;
	hspi->TxXferSize = Size;
	hspi->TxXferCount = Size;
	
	hspi->pRxBuffPtr = (uint8_t *)pRxData;
	hspi->RxXferSize = Size;
	hspi->RxXferCount = Size;
	
	len = (hspi->TxXferCount > BLOCK_SIZE) ? BLOCK_SIZE : hspi->TxXferCount;
	__HAL_SPI_SET_CLK_NUM(hspi, (len * 8));
	
	for (i = 0; i < hspi->TxXferCount; i++)
	{
		if (i == 4)
		{
			break;
		}
		data |= ((hspi->pTxBuffPtr + hspi->TxXferSize - hspi->TxXferCount)[i] << (i * 8));
	}
	hspi->Instance->TXDATA = data;
	hspi->TxXferCount -= i;
	
	__HAL_SPI_ENABLE_TXRX(hspi);
	__HAL_SPI_CLEAR_FLAG(hspi, (SPI_INT_SRC_DONE | SPI_INT_SRC_TXOV | SPI_INT_SRC_TXUN | SPI_INT_SRC_TXRDY | 
									SPI_INT_SRC_RXOV | SPI_INT_SRC_RXUN | SPI_INT_SRC_RXRDY));
	__HAL_SPI_ENABLE_IT(hspi, (SPI_INT_MASK_DONE | SPI_INT_MASK_TXUN | SPI_INT_SRC_TXRDY | SPI_INT_MASK_RXOV | SPI_INT_SRC_RXRDY));
	
	__HAL_SPI_SET_START(hspi);
error:
	__HAL_UNLOCK(hspi);
	return errorcode;
}

/**
  * @brief  Transmit an amount of data in non-blocking mode with DMA.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pData pointer to data buffer
  * @param  Size amount of data to be sent
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size)
{
	HAL_StatusTypeDef errorcode = HAL_OK;
	uint32_t len = 0;
	
	assert_param(IS_SPI_DMA_HANDLE(hspi->hdmatx));
	
	__HAL_LOCK(hspi);
	if (hspi->State != HAL_SPI_STATE_READY)
	{
		errorcode = HAL_BUSY;
		goto error;
	}
	
	if ((pData == NULL) || (Size == 0U))
	{
		errorcode = HAL_ERROR;
		goto error;
	}
	__HAL_SPI_CLEAR_FIFO(hspi);
	hspi->State = HAL_SPI_STATE_BUSY_TX;
	hspi->ErrorCode = HAL_SPI_ERROR_NONE;
	hspi->pTxBuffPtr = (uint8_t *)pData;
	hspi->TxXferSize = Size;
	hspi->TxXferCount = Size;
	
	hspi->pRxBuffPtr = (uint8_t *)NULL;
	hspi->RxXferSize = 0U;
	hspi->RxXferCount = 0U;
	
	hspi->hdmatx->XferHalfCpltCallback = SPI_DMAHalfTransmitCplt;
	hspi->hdmatx->XferCpltCallback = SPI_DMATransmitCplt;
	hspi->hdmatx->XferAbortCallback = NULL;
	
	len = (hspi->TxXferCount > BLOCK_SIZE) ? BLOCK_SIZE : hspi->TxXferCount;
	hspi->TxXferCount -= len;
	__HAL_SPI_SET_CLK_NUM(hspi, (len * 8));
	if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, 
									(uint32_t)hspi->pTxBuffPtr, 
									(uint32_t)&hspi->Instance->TXDATA,
									len))
	{
		SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);
		errorcode = HAL_ERROR;
		hspi->State = HAL_SPI_STATE_READY;
		goto error;
	}
	__HAL_SPI_ENABLE_TX(hspi);
	__HAL_SPI_CLEAR_FLAG(hspi, (SPI_INT_SRC_DONE | SPI_INT_SRC_TXOV | SPI_INT_SRC_TXUN | SPI_INT_SRC_TXRDY));
	__HAL_SPI_ENABLE_IT(hspi, (SPI_INT_MASK_DONE | SPI_INT_MASK_TXUN));
	SET_BIT(hspi->Instance->MODE_CFG, SPI_MODE_CFG_TXDMA);
	__HAL_SPI_SET_START(hspi);
error:
	__HAL_UNLOCK(hspi);
	return errorcode;
}

/**
  * @brief  Receive an amount of data in non-blocking mode with DMA.
  * @note   In case of MASTER mode and SPI_DIRECTION_2LINES direction, hdmatx shall be defined.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pData pointer to data buffer
  * @note   When the CRC feature is enabled the pData Length must be Size + 1.
  * @param  Size amount of data to be sent
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size)
{
	HAL_StatusTypeDef errorcode = HAL_OK;
	uint32_t len = 0;
	
	assert_param(IS_SPI_DMA_HANDLE(hspi->hdmarx));
	
	__HAL_LOCK(hspi);
	
	if (hspi->State != HAL_SPI_STATE_READY)
	{
		errorcode = HAL_BUSY;
		goto error;
	}
	if ((pData == NULL) || (Size == 0U))
	{
		errorcode = HAL_ERROR;
		goto error;
	}
	__HAL_SPI_CLEAR_FIFO(hspi);
	hspi->State = HAL_SPI_STATE_BUSY_RX;
	hspi->ErrorCode = HAL_SPI_ERROR_NONE;
	hspi->pRxBuffPtr = (uint8_t *)pData;
	hspi->RxXferSize = Size;
	hspi->RxXferCount = Size;
	
	hspi->pTxBuffPtr = (uint8_t *)NULL;
	hspi->TxXferSize = 0U;
	hspi->TxXferCount = 0U;
	
	hspi->hdmarx->XferHalfCpltCallback = SPI_DMAHalfReceiveCplt;
	hspi->hdmarx->XferCpltCallback = SPI_DMAReceiveCplt;
	hspi->hdmarx->XferAbortCallback = NULL;
	
	len = (hspi->RxXferCount > BLOCK_SIZE) ? BLOCK_SIZE : hspi->RxXferCount;
	hspi->RxXferCount -= len;
	__HAL_SPI_SET_CLK_NUM(hspi, (len * 8));
	if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx,
									(uint32_t)&hspi->Instance->RXDATA,
									(uint32_t)hspi->pRxBuffPtr,
									len))
	{
		SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);
		errorcode = HAL_ERROR;
		hspi->State = HAL_SPI_STATE_READY;
		goto error;
	}
	__HAL_SPI_ENABLE_RX(hspi);
	__HAL_SPI_CLEAR_FLAG(hspi, (SPI_INT_SRC_DONE | SPI_INT_SRC_RXOV | SPI_INT_SRC_RXUN | SPI_INT_SRC_RXRDY));
	__HAL_SPI_ENABLE_IT(hspi, (SPI_INT_MASK_DONE | SPI_INT_MASK_RXOV));
	SET_BIT(hspi->Instance->MODE_CFG, SPI_MODE_CFG_RXDMA);
	__HAL_SPI_SET_START(hspi);
error:
	__HAL_UNLOCK(hspi);
	return errorcode;
}

/**
  * @brief  Transmit and Receive an amount of data in non-blocking mode with DMA.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pTxData pointer to transmission data buffer
  * @param  pRxData pointer to reception data buffer
  * @note   When the CRC feature is enabled the pRxData Length must be Size + 1
  * @param  Size amount of data to be sent
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,
                                              uint32_t Size)
{
	HAL_StatusTypeDef errorcode = HAL_OK;
	uint32_t len = 0;
	
	assert_param(IS_SPI_DMA_HANDLE(hspi->hdmatx));
	assert_param(IS_SPI_DMA_HANDLE(hspi->hdmarx));
	
	__HAL_LOCK(hspi);
	
	if (hspi->State != HAL_SPI_STATE_READY)
	{
		errorcode = HAL_BUSY;
		goto error;
	}
	if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U))
	{
		errorcode = HAL_ERROR;
		goto error;
	}
	__HAL_SPI_CLEAR_FIFO(hspi);
	hspi->State = HAL_SPI_STATE_BUSY_TX_RX;
	hspi->ErrorCode = HAL_SPI_ERROR_NONE;
	hspi->pTxBuffPtr = (uint8_t *)pTxData;
	hspi->TxXferSize = Size;
	hspi->TxXferCount = Size;
	
	hspi->pRxBuffPtr = (uint8_t *)pRxData;
	hspi->RxXferSize = Size;
	hspi->RxXferCount = Size;
	
	hspi->hdmatx->XferHalfCpltCallback = SPI_DMAHalfTransmitReceiveCplt;
	hspi->hdmatx->XferCpltCallback = SPI_DMATransmitReceiveCplt;
	hspi->hdmatx->XferAbortCallback = NULL;
	hspi->hdmarx->XferHalfCpltCallback = SPI_DMAHalfTransmitReceiveCplt;
	hspi->hdmarx->XferCpltCallback = SPI_DMATransmitReceiveCplt;
	hspi->hdmarx->XferAbortCallback = NULL;
	
	len = (hspi->TxXferCount > BLOCK_SIZE) ? BLOCK_SIZE : hspi->TxXferCount;
	hspi->TxXferCount -= len;
	hspi->RxXferCount -= len;
	__HAL_SPI_SET_CLK_NUM(hspi, (len * 8));
	if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, 
									(uint32_t)hspi->pTxBuffPtr, 
									(uint32_t)&hspi->Instance->TXDATA,
									len))
	{
		SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);
		errorcode = HAL_ERROR;
		hspi->State = HAL_SPI_STATE_READY;
		goto error;
	}
	if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmarx,
									(uint32_t)&hspi->Instance->RXDATA,
									(uint32_t)hspi->pRxBuffPtr,
									len))
	{
		SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);
		errorcode = HAL_ERROR;
		hspi->State = HAL_SPI_STATE_READY;
		goto error;
	}
	__HAL_SPI_ENABLE_TXRX(hspi);
	__HAL_SPI_CLEAR_FLAG(hspi, (SPI_INT_SRC_DONE | SPI_INT_SRC_TXOV | SPI_INT_SRC_TXUN | SPI_INT_SRC_TXRDY | 
									SPI_INT_SRC_RXOV | SPI_INT_SRC_RXUN | SPI_INT_SRC_RXRDY));
	__HAL_SPI_ENABLE_IT(hspi, (SPI_INT_MASK_DONE | SPI_INT_MASK_TXUN | SPI_INT_MASK_RXOV));
	SET_BIT(hspi->Instance->MODE_CFG, (SPI_MODE_CFG_TXDMA | SPI_MODE_CFG_RXDMA));
	__HAL_SPI_SET_START(hspi);
error:
	__HAL_UNLOCK(hspi);
	return errorcode;
}

/**
  * @brief  Pause the DMA Transfer.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for the specified SPI module.
  * @retval HAL status
  */											  
HAL_StatusTypeDef HAL_SPI_DMAPause(SPI_HandleTypeDef *hspi)
{
	__HAL_LOCK(hspi);
	CLEAR_BIT(hspi->Instance->MODE_CFG, (SPI_MODE_CFG_TXDMA | SPI_MODE_CFG_RXDMA));
	__HAL_UNLOCK(hspi);
	
	return HAL_OK;
}

/**
  * @brief  Resume the DMA Transfer.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for the specified SPI module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_DMAResume(SPI_HandleTypeDef *hspi)
{
	__HAL_LOCK(hspi);
	if (hspi->State == HAL_SPI_STATE_BUSY_TX)
	{
		SET_BIT(hspi->Instance->MODE_CFG, SPI_MODE_CFG_TXDMA);
	}
	else if (hspi->State == HAL_SPI_STATE_BUSY_RX)
	{
		SET_BIT(hspi->Instance->MODE_CFG, SPI_MODE_CFG_RXDMA);
	}
	else if (hspi->State == HAL_SPI_STATE_BUSY_TX_RX)
	{
		SET_BIT(hspi->Instance->MODE_CFG, (SPI_MODE_CFG_TXDMA | SPI_MODE_CFG_RXDMA));
	}
	__HAL_UNLOCK(hspi);
	
	return HAL_OK;
}

/**
  * @brief  Stop the DMA Transfer.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for the specified SPI module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_DMAStop(SPI_HandleTypeDef *hspi)
{
	HAL_StatusTypeDef errorcode = HAL_OK;
	
	if (hspi->hdmatx != NULL)
	{
		if (HAL_OK != HAL_DMA_Abort(hspi->hdmatx))
		{
			SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);
			errorcode = HAL_ERROR;
		}
	}
	if (hspi->hdmarx != NULL)
	{
		if (HAL_OK != HAL_DMA_Abort(hspi->hdmarx))
		{
			SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);
			errorcode = HAL_ERROR;
		}
	}
	
	CLEAR_BIT(hspi->Instance->MODE_CFG, (SPI_MODE_CFG_TXDMA | SPI_MODE_CFG_RXDMA));
	hspi->State = HAL_SPI_STATE_READY;
	return errorcode;
}

/**
  * @brief  Handle SPI interrupt request.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for the specified SPI module.
  * @retval None
  */
void HAL_SPI_IRQHandler(SPI_HandleTypeDef *hspi)
{
	uint32_t itmask = hspi->Instance->INT_MASK;
	uint32_t itflag = hspi->Instance->INT_SRC;
	
	__HAL_SPI_CLEAR_FLAG(hspi, itflag);
	if (hspi->Instance->CH_CFG & SPI_CH_CFG_TXON)
	{
		if (((itflag & SPI_INT_SRC_TXRDY) == SPI_INT_SRC_TXRDY) && ((itmask & SPI_INT_MASK_TXRDY) == RESET))
		{
			SPI_Transmit_IT(hspi);
		}
		if (((itflag & SPI_INT_SRC_DONE) == SPI_INT_SRC_DONE) && ((itmask & SPI_INT_MASK_DONE) == RESET))
		{
			SPI_EndTransmit_IT(hspi);
		}
		if (((itflag & SPI_INT_SRC_TXUN) == SPI_INT_SRC_TXUN) && ((itmask & SPI_INT_MASK_TXUN) == RESET))
		{
			SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_TXERR);
			HAL_SPI_ErrorCallback(hspi);
		}
	}
	if (hspi->Instance->CH_CFG & SPI_CH_CFG_RXON)
	{
		if (((itflag & SPI_INT_SRC_RXRDY) == SPI_INT_SRC_RXRDY) && ((itmask & SPI_INT_MASK_RXRDY) == RESET))
		{
			SPI_Receive_IT(hspi);
		}
		if (((itflag & SPI_INT_SRC_DONE) == SPI_INT_SRC_DONE) && ((itmask & SPI_INT_MASK_DONE) == RESET))
		{
			SPI_EndReceive_IT(hspi);
		}
		if (((itflag & SPI_INT_SRC_RXOV) == SPI_INT_SRC_RXOV) && ((itmask & SPI_INT_MASK_RXOV) == RESET))
		{
			SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_RXERR);
			HAL_SPI_ErrorCallback(hspi);
		}
	}
}

/**
  * @brief  Tx Transfer completed callback.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval None
  */
__attribute__((weak)) void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
	UNUSED(hspi);
}

/**
  * @brief  Rx Transfer completed callback.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval None
  */
__attribute__((weak)) void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
	UNUSED(hspi);
}

/**
  * @brief  Tx and Rx Transfer completed callback.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval None
  */
__attribute__((weak)) void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
	UNUSED(hspi);
}

/**
  * @brief  Tx Half Transfer completed callback.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval None
  */
__attribute__((weak)) void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
	UNUSED(hspi);
}

/**
  * @brief  Rx Half Transfer completed callback.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval None
  */
__attribute__((weak)) void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
	UNUSED(hspi);
}

/**
  * @brief  Tx and Rx Half Transfer callback.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval None
  */
__attribute__((weak)) void HAL_SPI_TxRxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
	UNUSED(hspi);
}

/**
  * @brief  SPI error callback.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval None
  */
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
	UNUSED(hspi);
}

/**
  * @brief  Return the SPI handle state.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval SPI state
  */
HAL_SPI_StateTypeDef HAL_SPI_GetState(SPI_HandleTypeDef *hspi)
{
	return hspi->State;
}

/**
  * @brief  Return the SPI error code.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @retval SPI error code in bitmap format
  */
uint32_t HAL_SPI_GetError(SPI_HandleTypeDef *hspi)
{
	return hspi->ErrorCode;
}

/**
  * @brief  DMA SPI transmit process complete callback.
  * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
  *               the configuration information for the specified DMA module.
  * @retval None
  */
static void SPI_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
	SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent);
	
	if ((hspi->TxXferCount == 0) && ((hdma->Init.Mode == DMA_MODE_NORMAL_SINGLE) || (hdma->Init.Mode == DMA_MODE_LINK_SINGLE)))
	{
		CLEAR_BIT(hspi->Instance->MODE_CFG, SPI_MODE_CFG_TXDMA);
	}
}

/**
  * @brief  DMA SPI half transmit process complete callback.
  * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
  *               the configuration information for the specified DMA module.
  * @retval None
  */
static void SPI_DMAHalfTransmitCplt(DMA_HandleTypeDef *hdma)
{
	SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent);
	
	if (hspi->TxXferSize <= BLOCK_SIZE)
	{
		HAL_SPI_TxHalfCpltCallback(hspi);
	}
}

/**
  * @brief  DMA SPI receive process complete callback.
  * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
  *               the configuration information for the specified DMA module.
  * @retval None
  */
static void SPI_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
	SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent);
	
	if ((hspi->RxXferCount == 0) && ((hdma->Init.Mode == DMA_MODE_NORMAL_SINGLE) || (hdma->Init.Mode == DMA_MODE_LINK_SINGLE)))
	{
		CLEAR_BIT(hspi->Instance->MODE_CFG, SPI_MODE_CFG_RXDMA);
	}
}

/**
  * @brief  DMA SPI half receive process complete callback
  * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
  *               the configuration information for the specified DMA module.
  * @retval None
  */
static void SPI_DMAHalfReceiveCplt(DMA_HandleTypeDef *hdma)
{
	SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent);
	
	if (hspi->RxXferSize <= BLOCK_SIZE)
	{
		HAL_SPI_RxHalfCpltCallback(hspi);
	}
}

/**
  * @brief  DMA SPI transmit receive process complete callback.
  * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
  *               the configuration information for the specified DMA module.
  * @retval None
  */
static void SPI_DMATransmitReceiveCplt(DMA_HandleTypeDef *hdma)
{
	SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent);
	
	if ((hdma->Init.Mode == DMA_MODE_NORMAL_SINGLE) || (hdma->Init.Mode == DMA_MODE_LINK_SINGLE))
	{
		if ((hspi->hdmarx == hdma) && (hspi->RxXferCount == 0))
		{
			CLEAR_BIT(hspi->Instance->MODE_CFG, SPI_MODE_CFG_RXDMA);
		}
		if ((hspi->hdmatx == hdma) && (hspi->TxXferCount == 0))
		{
			CLEAR_BIT(hspi->Instance->MODE_CFG, SPI_MODE_CFG_TXDMA);
		}
	}
}

/**
  * @brief  DMA SPI half transmit receive process complete callback.
  * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
  *               the configuration information for the specified DMA module.
  * @retval None
  */
static void SPI_DMAHalfTransmitReceiveCplt(DMA_HandleTypeDef *hdma)
{
	SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)(((DMA_HandleTypeDef *)hdma)->Parent);
	
	HAL_SPI_TxRxHalfCpltCallback(hspi);
}

static void SPI_Transmit_IT(SPI_HandleTypeDef *hspi)
{
	uint32_t data = 0, i = 0;
	
	if (((hspi->TxXferSize - hspi->TxXferCount) % BLOCK_SIZE) == 0)
	{
		return;
	}
	for (i = 0; i < hspi->TxXferCount; i++)
	{
		if (i == 4)
		{
			break;
		}
		data |= ((hspi->pTxBuffPtr + hspi->TxXferSize - hspi->TxXferCount)[i] << (i * 8));
	}
	hspi->Instance->TXDATA = data;
	hspi->TxXferCount -= i;
}

static void SPI_EndTransmit_IT(SPI_HandleTypeDef *hspi)
{
	uint32_t len = 0;
	
	len = (hspi->TxXferCount > BLOCK_SIZE) ? BLOCK_SIZE : hspi->TxXferCount;
	if (len == 0)
	{
	#if 0
		if ((hspi->hdmatx->Init.Mode == DMA_MODE_NORMAL_CIRCULAR) || (hspi->hdmatx->Init.Mode == DMA_MODE_LINK_CIRCULAR))
		{
			hspi->TxXferCount = hspi->TxXferSize;
			len = (hspi->TxXferCount > BLOCK_SIZE) ? BLOCK_SIZE : hspi->TxXferCount;
			__HAL_SPI_SET_CLK_NUM(hspi, len * 8);
			__HAL_SPI_SET_START(hspi);
		}
		else //if ((hspi->hdmatx->Init.Mode == DMA_MODE_NORMAL_SINGLE) || (hspi->hdmatx->Init.Mode == DMA_MODE_LINK_SINGLE))
	#endif
		{
			__HAL_SPI_DISABLE_IT(hspi, (SPI_INT_MASK_DONE | SPI_INT_MASK_TXRDY | SPI_INT_MASK_TXUN));
			if (hspi->State == HAL_SPI_STATE_BUSY_TX)
			{
				__HAL_SPI_DISABLE_TX(hspi);
				hspi->State = HAL_SPI_STATE_READY;
				HAL_SPI_TxCpltCallback(hspi);
			}
			else if (hspi->State == HAL_SPI_STATE_BUSY_TX_RX)
			{
				__HAL_SPI_DISABLE_TX(hspi);
				__HAL_SPI_DISABLE_RX(hspi);
				hspi->State = HAL_SPI_STATE_READY;
				HAL_SPI_TxRxCpltCallback(hspi);
			}
		}
	}
	else
	{
		__HAL_SPI_SET_CLK_NUM(hspi, (len * 8));
		if ((hspi->Instance->MODE_CFG & SPI_MODE_CFG_TXDMA) == SPI_MODE_CFG_TXDMA)
		{
			HAL_DMA_Start_IT(hspi->hdmatx, 
							(uint32_t)(hspi->pTxBuffPtr + (hspi->TxXferSize - hspi->TxXferCount)), 
							(uint32_t)&(hspi->Instance->TXDATA),
							len);
			hspi->TxXferCount -= len;
		}
		else
		{
			uint32_t data = 0, i = 0;
			for (i = 0; i < hspi->TxXferCount; i++)
			{
				if (i == 4)
				{
					break;
				}
				data |= ((hspi->pTxBuffPtr + hspi->TxXferSize - hspi->TxXferCount)[i] << (i * 8));
			}
			hspi->Instance->TXDATA = data;
			hspi->TxXferCount -= i;
		}
		__HAL_SPI_SET_START(hspi);
	}
}

static void SPI_Receive_IT(SPI_HandleTypeDef *hspi)
{
	uint32_t i = 0, data = 0;
	uint32_t fifo_count = __HAL_SPI_GET_RXFIFO(hspi) / 4;
	while (fifo_count > 0)
	{
		data = READ_REG(hspi->Instance->RXDATA);
		for (i = 0; i < 4; i++)
		{
			if (i == hspi->RxXferCount)
			{
				break;
			}
			(hspi->pRxBuffPtr + hspi->RxXferSize - hspi->RxXferCount)[i] = (data >> (i * 8)) & 0xFF;
		}
		hspi->RxXferCount -= i;
		fifo_count--;
		if((hspi->RxXferCount == 0))
		{
			break;
		}
	}
}

static void SPI_EndReceive_IT(SPI_HandleTypeDef *hspi)
{
	uint32_t len = 0;
	
	len = (hspi->RxXferCount > BLOCK_SIZE) ? BLOCK_SIZE : hspi->RxXferCount;
	if (len == 0)
	{
	#if 0
		if ((hspi->hdmatx->Init.Mode == DMA_MODE_NORMAL_CIRCULAR) || (hspi->hdmatx->Init.Mode == DMA_MODE_LINK_CIRCULAR))
		{
			hspi->RxXferCount = hspi->RxXferSize;
			len = (hspi->RxXferCount > BLOCK_SIZE) ? BLOCK_SIZE : hspi->RxXferCount;
			__HAL_SPI_SET_CLK_NUM(hspi, len * 8);
			__HAL_SPI_SET_START(hspi);
		}
		else //if ((hspi->hdmatx->Init.Mode == DMA_MODE_NORMAL_SINGLE) || (hspi->hdmatx->Init.Mode == DMA_MODE_LINK_SINGLE))
	#endif
		{
			__HAL_SPI_DISABLE_IT(hspi, (SPI_INT_MASK_DONE | SPI_INT_MASK_RXRDY | SPI_INT_MASK_RXOV));
			if (hspi->State == HAL_SPI_STATE_BUSY_RX)
			{
				__HAL_SPI_DISABLE_RX(hspi);
				hspi->State = HAL_SPI_STATE_READY;
				HAL_SPI_RxCpltCallback(hspi);
			}
			else if (hspi->State == HAL_SPI_STATE_BUSY_TX_RX)
			{
				__HAL_SPI_DISABLE_TX(hspi);
				__HAL_SPI_DISABLE_RX(hspi);
				hspi->State = HAL_SPI_STATE_READY;
				HAL_SPI_TxRxCpltCallback(hspi);
			}
		}
	}
	else
	{
		__HAL_SPI_SET_CLK_NUM(hspi, len * 8);
		if ((hspi->Instance->MODE_CFG & SPI_MODE_CFG_RXDMA) == SPI_MODE_CFG_RXDMA)
		{
			HAL_DMA_Start_IT(hspi->hdmarx, 
							(uint32_t)&(hspi->Instance->RXDATA),
							(uint32_t)(hspi->pRxBuffPtr + (hspi->RxXferSize - hspi->RxXferCount)), 
							len);
			hspi->RxXferCount -= len;
		}
		else
		{
			SPI_Receive_IT(hspi);
		}
		__HAL_SPI_SET_START(hspi);
	}
}